package com.p6spy.engine.common;

import java.sql.ResultSet;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import com.p6spy.engine.logging.Category;

/**
 * @author Quinton McCombs
 * @since 09/2013
 */
public class ResultSetInformation implements Loggable {

    private final StatementInformation statementInformation;
    private ResultSet resultSet;
    private final String query;
    private final Map<String, Value> resultMap = new LinkedHashMap<String, Value>();
    private int currRow = -1;
    private int lastRowLogged = -1;

    public ResultSetInformation(final StatementInformation statementInformation) {
        this.statementInformation = statementInformation;
        this.query = statementInformation.getStatementQuery();
    }

    /**
     * Generates log message with column values accessed if the row's column values have not already been logged.
     */
    public void generateLogMessage() {
        if (lastRowLogged != currRow) {
            P6LogQuery.log(Category.RESULTSET, this);
            lastRowLogged = currRow;
        }
    }

    public int getCurrRow() {
        return currRow;
    }

    public void incrementCurrRow() {
        this.currRow++;
        this.resultMap.clear();
    }

    public void setColumnValue(String columnName, Object value) {
        resultMap.put(columnName, new Value(value));
    }

    @Override
    public String getSql() {
        return query;
    }

    @Override
    public String getSqlWithValues() {
        final StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Value> entry : resultMap.entrySet()) {
            if (sb.length() > 0) {
                sb.append(", ");
            }
            sb.append(entry.getKey());
            sb.append(" = ");
            sb.append(entry.getValue() != null ? entry.getValue().toString() : new Value().toString());
        }

        return sb.toString();
    }

    /**
     * Returns column/value map for the last row read.
     * <p>
     * NOTE: Only values that were retrieved from {@link ResultSet}
     * ({@link ResultSet#getString(int)}, {@link ResultSet#getBoolean(int)}, etc.) will be returned.
     */
    public Map<String, Value> getResultMap() {
        return Collections.unmodifiableMap(resultMap);
    }

    public StatementInformation getStatementInformation() {
        return statementInformation;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ConnectionInformation getConnectionInformation() {
        return this.statementInformation.getConnectionInformation();
    }

    public ResultSet getResultSet() {
        return resultSet;
    }

    public void setResultSet(ResultSet resultSet) {
        this.resultSet = resultSet;
    }
}
